{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T11:41:35.687364Z",
     "start_time": "2019-11-12T11:41:34.775595Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "    <div class=\"bk-root\">\n",
       "        <a href=\"https://bokeh.pydata.org\" target=\"_blank\" class=\"bk-logo bk-logo-small bk-logo-notebook\"></a>\n",
       "        <span id=\"1001\">Loading BokehJS ...</span>\n",
       "    </div>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/javascript": [
       "\n",
       "(function(root) {\n",
       "  function now() {\n",
       "    return new Date();\n",
       "  }\n",
       "\n",
       "  var force = true;\n",
       "\n",
       "  if (typeof (root._bokeh_onload_callbacks) === \"undefined\" || force === true) {\n",
       "    root._bokeh_onload_callbacks = [];\n",
       "    root._bokeh_is_loading = undefined;\n",
       "  }\n",
       "\n",
       "  var JS_MIME_TYPE = 'application/javascript';\n",
       "  var HTML_MIME_TYPE = 'text/html';\n",
       "  var EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n",
       "  var CLASS_NAME = 'output_bokeh rendered_html';\n",
       "\n",
       "  /**\n",
       "   * Render data to the DOM node\n",
       "   */\n",
       "  function render(props, node) {\n",
       "    var script = document.createElement(\"script\");\n",
       "    node.appendChild(script);\n",
       "  }\n",
       "\n",
       "  /**\n",
       "   * Handle when an output is cleared or removed\n",
       "   */\n",
       "  function handleClearOutput(event, handle) {\n",
       "    var cell = handle.cell;\n",
       "\n",
       "    var id = cell.output_area._bokeh_element_id;\n",
       "    var server_id = cell.output_area._bokeh_server_id;\n",
       "    // Clean up Bokeh references\n",
       "    if (id != null && id in Bokeh.index) {\n",
       "      Bokeh.index[id].model.document.clear();\n",
       "      delete Bokeh.index[id];\n",
       "    }\n",
       "\n",
       "    if (server_id !== undefined) {\n",
       "      // Clean up Bokeh references\n",
       "      var cmd = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n",
       "      cell.notebook.kernel.execute(cmd, {\n",
       "        iopub: {\n",
       "          output: function(msg) {\n",
       "            var id = msg.content.text.trim();\n",
       "            if (id in Bokeh.index) {\n",
       "              Bokeh.index[id].model.document.clear();\n",
       "              delete Bokeh.index[id];\n",
       "            }\n",
       "          }\n",
       "        }\n",
       "      });\n",
       "      // Destroy server and session\n",
       "      var cmd = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n",
       "      cell.notebook.kernel.execute(cmd);\n",
       "    }\n",
       "  }\n",
       "\n",
       "  /**\n",
       "   * Handle when a new output is added\n",
       "   */\n",
       "  function handleAddOutput(event, handle) {\n",
       "    var output_area = handle.output_area;\n",
       "    var output = handle.output;\n",
       "\n",
       "    // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n",
       "    if ((output.output_type != \"display_data\") || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n",
       "      return\n",
       "    }\n",
       "\n",
       "    var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n",
       "\n",
       "    if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n",
       "      toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n",
       "      // store reference to embed id on output_area\n",
       "      output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n",
       "    }\n",
       "    if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n",
       "      var bk_div = document.createElement(\"div\");\n",
       "      bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n",
       "      var script_attrs = bk_div.children[0].attributes;\n",
       "      for (var i = 0; i < script_attrs.length; i++) {\n",
       "        toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n",
       "      }\n",
       "      // store reference to server id on output_area\n",
       "      output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n",
       "    }\n",
       "  }\n",
       "\n",
       "  function register_renderer(events, OutputArea) {\n",
       "\n",
       "    function append_mime(data, metadata, element) {\n",
       "      // create a DOM node to render to\n",
       "      var toinsert = this.create_output_subarea(\n",
       "        metadata,\n",
       "        CLASS_NAME,\n",
       "        EXEC_MIME_TYPE\n",
       "      );\n",
       "      this.keyboard_manager.register_events(toinsert);\n",
       "      // Render to node\n",
       "      var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n",
       "      render(props, toinsert[toinsert.length - 1]);\n",
       "      element.append(toinsert);\n",
       "      return toinsert\n",
       "    }\n",
       "\n",
       "    /* Handle when an output is cleared or removed */\n",
       "    events.on('clear_output.CodeCell', handleClearOutput);\n",
       "    events.on('delete.Cell', handleClearOutput);\n",
       "\n",
       "    /* Handle when a new output is added */\n",
       "    events.on('output_added.OutputArea', handleAddOutput);\n",
       "\n",
       "    /**\n",
       "     * Register the mime type and append_mime function with output_area\n",
       "     */\n",
       "    OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n",
       "      /* Is output safe? */\n",
       "      safe: true,\n",
       "      /* Index of renderer in `output_area.display_order` */\n",
       "      index: 0\n",
       "    });\n",
       "  }\n",
       "\n",
       "  // register the mime type if in Jupyter Notebook environment and previously unregistered\n",
       "  if (root.Jupyter !== undefined) {\n",
       "    var events = require('base/js/events');\n",
       "    var OutputArea = require('notebook/js/outputarea').OutputArea;\n",
       "\n",
       "    if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n",
       "      register_renderer(events, OutputArea);\n",
       "    }\n",
       "  }\n",
       "\n",
       "  \n",
       "  if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n",
       "    root._bokeh_timeout = Date.now() + 5000;\n",
       "    root._bokeh_failed_load = false;\n",
       "  }\n",
       "\n",
       "  var NB_LOAD_WARNING = {'data': {'text/html':\n",
       "     \"<div style='background-color: #fdd'>\\n\"+\n",
       "     \"<p>\\n\"+\n",
       "     \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n",
       "     \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n",
       "     \"</p>\\n\"+\n",
       "     \"<ul>\\n\"+\n",
       "     \"<li>re-rerun `output_notebook()` to attempt to load from CDN again, or</li>\\n\"+\n",
       "     \"<li>use INLINE resources instead, as so:</li>\\n\"+\n",
       "     \"</ul>\\n\"+\n",
       "     \"<code>\\n\"+\n",
       "     \"from bokeh.resources import INLINE\\n\"+\n",
       "     \"output_notebook(resources=INLINE)\\n\"+\n",
       "     \"</code>\\n\"+\n",
       "     \"</div>\"}};\n",
       "\n",
       "  function display_loaded() {\n",
       "    var el = document.getElementById(\"1001\");\n",
       "    if (el != null) {\n",
       "      el.textContent = \"BokehJS is loading...\";\n",
       "    }\n",
       "    if (root.Bokeh !== undefined) {\n",
       "      if (el != null) {\n",
       "        el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n",
       "      }\n",
       "    } else if (Date.now() < root._bokeh_timeout) {\n",
       "      setTimeout(display_loaded, 100)\n",
       "    }\n",
       "  }\n",
       "\n",
       "\n",
       "  function run_callbacks() {\n",
       "    try {\n",
       "      root._bokeh_onload_callbacks.forEach(function(callback) { callback() });\n",
       "    }\n",
       "    finally {\n",
       "      delete root._bokeh_onload_callbacks\n",
       "    }\n",
       "    console.info(\"Bokeh: all callbacks have finished\");\n",
       "  }\n",
       "\n",
       "  function load_libs(js_urls, callback) {\n",
       "    root._bokeh_onload_callbacks.push(callback);\n",
       "    if (root._bokeh_is_loading > 0) {\n",
       "      console.log(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n",
       "      return null;\n",
       "    }\n",
       "    if (js_urls == null || js_urls.length === 0) {\n",
       "      run_callbacks();\n",
       "      return null;\n",
       "    }\n",
       "    console.log(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n",
       "    root._bokeh_is_loading = js_urls.length;\n",
       "    for (var i = 0; i < js_urls.length; i++) {\n",
       "      var url = js_urls[i];\n",
       "      var s = document.createElement('script');\n",
       "      s.src = url;\n",
       "      s.async = false;\n",
       "      s.onreadystatechange = s.onload = function() {\n",
       "        root._bokeh_is_loading--;\n",
       "        if (root._bokeh_is_loading === 0) {\n",
       "          console.log(\"Bokeh: all BokehJS libraries loaded\");\n",
       "          run_callbacks()\n",
       "        }\n",
       "      };\n",
       "      s.onerror = function() {\n",
       "        console.warn(\"failed to load library \" + url);\n",
       "      };\n",
       "      console.log(\"Bokeh: injecting script tag for BokehJS library: \", url);\n",
       "      document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
       "    }\n",
       "  };var element = document.getElementById(\"1001\");\n",
       "  if (element == null) {\n",
       "    console.log(\"Bokeh: ERROR: autoload.js configured with elementid '1001' but no matching script tag was found. \")\n",
       "    return false;\n",
       "  }\n",
       "\n",
       "  var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-1.0.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-1.0.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-1.0.0.min.js\"];\n",
       "\n",
       "  var inline_js = [\n",
       "    function(Bokeh) {\n",
       "      Bokeh.set_log_level(\"info\");\n",
       "    },\n",
       "    \n",
       "    function(Bokeh) {\n",
       "      \n",
       "    },\n",
       "    function(Bokeh) {\n",
       "      console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-1.0.0.min.css\");\n",
       "      Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-1.0.0.min.css\");\n",
       "      console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.0.min.css\");\n",
       "      Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.0.min.css\");\n",
       "      console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-tables-1.0.0.min.css\");\n",
       "      Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-tables-1.0.0.min.css\");\n",
       "    }\n",
       "  ];\n",
       "\n",
       "  function run_inline_js() {\n",
       "    \n",
       "    if ((root.Bokeh !== undefined) || (force === true)) {\n",
       "      for (var i = 0; i < inline_js.length; i++) {\n",
       "        inline_js[i].call(root, root.Bokeh);\n",
       "      }if (force === true) {\n",
       "        display_loaded();\n",
       "      }} else if (Date.now() < root._bokeh_timeout) {\n",
       "      setTimeout(run_inline_js, 100);\n",
       "    } else if (!root._bokeh_failed_load) {\n",
       "      console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n",
       "      root._bokeh_failed_load = true;\n",
       "    } else if (force !== true) {\n",
       "      var cell = $(document.getElementById(\"1001\")).parents('.cell').data().cell;\n",
       "      cell.output_area.append_execute_result(NB_LOAD_WARNING)\n",
       "    }\n",
       "\n",
       "  }\n",
       "\n",
       "  if (root._bokeh_is_loading === 0) {\n",
       "    console.log(\"Bokeh: BokehJS loaded, going straight to plotting\");\n",
       "    run_inline_js();\n",
       "  } else {\n",
       "    load_libs(js_urls, function() {\n",
       "      console.log(\"Bokeh: BokehJS plotting callback run at\", now());\n",
       "      run_inline_js();\n",
       "    });\n",
       "  }\n",
       "}(window));"
      ],
      "application/vnd.bokehjs_load.v0+json": "\n(function(root) {\n  function now() {\n    return new Date();\n  }\n\n  var force = true;\n\n  if (typeof (root._bokeh_onload_callbacks) === \"undefined\" || force === true) {\n    root._bokeh_onload_callbacks = [];\n    root._bokeh_is_loading = undefined;\n  }\n\n  \n\n  \n  if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n    root._bokeh_timeout = Date.now() + 5000;\n    root._bokeh_failed_load = false;\n  }\n\n  var NB_LOAD_WARNING = {'data': {'text/html':\n     \"<div style='background-color: #fdd'>\\n\"+\n     \"<p>\\n\"+\n     \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n     \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n     \"</p>\\n\"+\n     \"<ul>\\n\"+\n     \"<li>re-rerun `output_notebook()` to attempt to load from CDN again, or</li>\\n\"+\n     \"<li>use INLINE resources instead, as so:</li>\\n\"+\n     \"</ul>\\n\"+\n     \"<code>\\n\"+\n     \"from bokeh.resources import INLINE\\n\"+\n     \"output_notebook(resources=INLINE)\\n\"+\n     \"</code>\\n\"+\n     \"</div>\"}};\n\n  function display_loaded() {\n    var el = document.getElementById(\"1001\");\n    if (el != null) {\n      el.textContent = \"BokehJS is loading...\";\n    }\n    if (root.Bokeh !== undefined) {\n      if (el != null) {\n        el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n      }\n    } else if (Date.now() < root._bokeh_timeout) {\n      setTimeout(display_loaded, 100)\n    }\n  }\n\n\n  function run_callbacks() {\n    try {\n      root._bokeh_onload_callbacks.forEach(function(callback) { callback() });\n    }\n    finally {\n      delete root._bokeh_onload_callbacks\n    }\n    console.info(\"Bokeh: all callbacks have finished\");\n  }\n\n  function load_libs(js_urls, callback) {\n    root._bokeh_onload_callbacks.push(callback);\n    if (root._bokeh_is_loading > 0) {\n      console.log(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n      return null;\n    }\n    if (js_urls == null || js_urls.length === 0) {\n      run_callbacks();\n      return null;\n    }\n    console.log(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n    root._bokeh_is_loading = js_urls.length;\n    for (var i = 0; i < js_urls.length; i++) {\n      var url = js_urls[i];\n      var s = document.createElement('script');\n      s.src = url;\n      s.async = false;\n      s.onreadystatechange = s.onload = function() {\n        root._bokeh_is_loading--;\n        if (root._bokeh_is_loading === 0) {\n          console.log(\"Bokeh: all BokehJS libraries loaded\");\n          run_callbacks()\n        }\n      };\n      s.onerror = function() {\n        console.warn(\"failed to load library \" + url);\n      };\n      console.log(\"Bokeh: injecting script tag for BokehJS library: \", url);\n      document.getElementsByTagName(\"head\")[0].appendChild(s);\n    }\n  };var element = document.getElementById(\"1001\");\n  if (element == null) {\n    console.log(\"Bokeh: ERROR: autoload.js configured with elementid '1001' but no matching script tag was found. \")\n    return false;\n  }\n\n  var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-1.0.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-1.0.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-1.0.0.min.js\"];\n\n  var inline_js = [\n    function(Bokeh) {\n      Bokeh.set_log_level(\"info\");\n    },\n    \n    function(Bokeh) {\n      \n    },\n    function(Bokeh) {\n      console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-1.0.0.min.css\");\n      Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-1.0.0.min.css\");\n      console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.0.min.css\");\n      Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.0.min.css\");\n      console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-tables-1.0.0.min.css\");\n      Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-tables-1.0.0.min.css\");\n    }\n  ];\n\n  function run_inline_js() {\n    \n    if ((root.Bokeh !== undefined) || (force === true)) {\n      for (var i = 0; i < inline_js.length; i++) {\n        inline_js[i].call(root, root.Bokeh);\n      }if (force === true) {\n        display_loaded();\n      }} else if (Date.now() < root._bokeh_timeout) {\n      setTimeout(run_inline_js, 100);\n    } else if (!root._bokeh_failed_load) {\n      console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n      root._bokeh_failed_load = true;\n    } else if (force !== true) {\n      var cell = $(document.getElementById(\"1001\")).parents('.cell').data().cell;\n      cell.output_area.append_execute_result(NB_LOAD_WARNING)\n    }\n\n  }\n\n  if (root._bokeh_is_loading === 0) {\n    console.log(\"Bokeh: BokehJS loaded, going straight to plotting\");\n    run_inline_js();\n  } else {\n    load_libs(js_urls, function() {\n      console.log(\"Bokeh: BokehJS plotting callback run at\", now());\n      run_inline_js();\n    });\n  }\n}(window));"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.ticker as ticker\n",
    "import torchvision.datasets as dsets\n",
    "import torchvision.transforms as transforms\n",
    "from torch.utils.data import DataLoader\n",
    "import random\n",
    "import time\n",
    "\n",
    "from bokeh.io import show, output_notebook\n",
    "from bokeh.plotting import figure, gridplot\n",
    "from bokeh.models import LinearAxis, Range1d\n",
    "output_notebook()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### GPU\n",
    "指定使用的 GPU 编号。  \n",
    "`watch -n 1 nvidia-smi` 实时查看 GPU 的运行状态。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T11:41:35.878002Z",
     "start_time": "2019-11-12T11:41:35.688894Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.cuda.set_device(\"cuda:3\")\n",
    "torch.cuda.current_device()\n",
    "# device = torch.device(\"cuda:5\")\n",
    "# xxx.to(device)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-02T15:34:18.036850Z",
     "start_time": "2019-11-02T15:34:18.032937Z"
    }
   },
   "source": [
    "### Data\n",
    "读入 dataset 中的 `eng-fra.txt`。  \n",
    "\n",
    "- `prepareData` 先将文本中的所有行读入，每行可以产生一个英语和法语的对，作为训练集。  \n",
    "`reverse=True` 时，输入英文，输出法语；反之则颠倒。  \n",
    "- 过滤：只选取英文以 `eng_prefixes` 开头的句子，且每句话最多保留10个单词，加快训练速度。  \n",
    "- `class Lang` 分别保存两种语言的词库，建立词典。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T11:41:36.001947Z",
     "start_time": "2019-11-12T11:41:35.890941Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('i am ',\n",
       " 'i m ',\n",
       " 'he is',\n",
       " 'he s ',\n",
       " 'she is',\n",
       " 'she s',\n",
       " 'you are',\n",
       " 'you re ',\n",
       " 'we are',\n",
       " 'we re ',\n",
       " 'they are',\n",
       " 'they re ')"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from lang import prepareData, eng_prefixes\n",
    "eng_prefixes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-10T08:28:32.616167Z",
     "start_time": "2019-11-10T08:28:32.609312Z"
    }
   },
   "source": [
    "Dataset, DataLoader产生自定义的训练数据，重写 Dataset 里的 `__init__`, `__len__` 和 `__getitem__` 方法。  \n",
    "将 `prepareData` 以及产生训练数据的部分放入 `Dataset.__init__`，方便后面进行 load."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-10T12:48:18.468318Z",
     "start_time": "2019-11-10T12:48:18.461612Z"
    }
   },
   "source": [
    "由于每个句子并不是统一长度，当 `train_loader.batch_size != 1` 时， 会因为句子长度不一样而失败。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T11:41:41.682045Z",
     "start_time": "2019-11-12T11:41:36.010033Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Reading lines...\n",
      "../dataset/eng-fra.txt\n",
      "Read 135842 sentence pairs\n",
      "Trimmed to 10853 sentence pairs\n",
      "Counting words...\n",
      "Counted words:\n",
      "fra 4489\n",
      "eng 2925\n"
     ]
    }
   ],
   "source": [
    "from dataset import TorchDataset, SOS_token, EOS_token\n",
    "batch_size = 1\n",
    "train_data = TorchDataset('eng', 'fra', reverse=True, repeat=1)\n",
    "train_loader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T11:41:41.689745Z",
     "start_time": "2019-11-12T11:41:41.683702Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[ 6],\n",
      "        [11],\n",
      "        [14],\n",
      "        [15],\n",
      "        [ 5],\n",
      "        [ 1]])\n",
      "tensor([[2],\n",
      "        [3],\n",
      "        [7],\n",
      "        [4],\n",
      "        [1]])\n",
      "['je suis en forme .', 'i m fit .']\n"
     ]
    }
   ],
   "source": [
    "(fra, eng), sentence = train_data[5]\n",
    "print(fra)\n",
    "print(eng)\n",
    "print(sentence)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Model\n",
    "定义编码网络和解码网络。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T11:41:41.830486Z",
     "start_time": "2019-11-12T11:41:41.692287Z"
    }
   },
   "outputs": [],
   "source": [
    "MAX_LENGTH = 10\n",
    "\n",
    "class EncoderRNN(nn.Module):\n",
    "    def __init__(self, dim_in, dim_hid, n_layers=1):\n",
    "        super().__init__()\n",
    "        self.n_layers = n_layers\n",
    "        self.dim_hid = dim_hid\n",
    "        self.embedding = nn.Embedding(dim_in, dim_hid)\n",
    "        self.gru = nn.GRU(dim_hid, dim_hid)\n",
    "    def forward(self, x, h):\n",
    "        em = self.embedding(x).view(1, 1, -1)\n",
    "        y = em\n",
    "        for i in range(self.n_layers):\n",
    "            y, h = self.gru(y, h)\n",
    "        return y, h\n",
    "    def initHidden(self):\n",
    "        return torch.zeros(1, 1, self.dim_hid).cuda()\n",
    "    \n",
    "class AttnDecoderRNN(nn.Module):\n",
    "    def __init__(self, dim_hid, dim_out, n_layers=1, dropout_prob=0.1, max_length=MAX_LENGTH):\n",
    "        super().__init__()\n",
    "        self.dim_hid = dim_hid\n",
    "        self.dim_out = dim_out\n",
    "        self.n_layers = n_layers\n",
    "        self.dropout_prob = dropout_prob\n",
    "        self.max_length = max_length\n",
    "        \n",
    "        self.embedding = nn.Embedding(self.dim_out, self.dim_hid)\n",
    "        self.attn = nn.Linear(self.dim_hid*2, self.max_length)\n",
    "        self.attn_combine = nn.Linear(self.dim_hid*2, self.dim_hid)\n",
    "        self.dropout = nn.Dropout(self.dropout_prob)\n",
    "        self.gru = nn.GRU(self.dim_hid, self.dim_hid)\n",
    "        self.fc = nn.Linear(self.dim_hid, self.dim_out)\n",
    "    def forward(self, x, h, encoded):\n",
    "        em = self.embedding(x).view(1, 1, -1)\n",
    "        em = self.dropout(em)\n",
    "        \n",
    "        attn_w = torch.nn.functional.softmax(self.attn(torch.cat((em[0], h[0]), 1)), dim=1)\n",
    "        attn_applied = torch.bmm(attn_w.unsqueeze(0), encoded.unsqueeze(0))\n",
    "        \n",
    "        y = torch.cat((em[0], attn_applied[0]), 1)\n",
    "        y = self.attn_combine(y).unsqueeze(0)\n",
    "        \n",
    "        for i in range(self.n_layers):\n",
    "            y = torch.relu(y)\n",
    "            y, h = self.gru(y, h)\n",
    "        \n",
    "        y = torch.nn.functional.log_softmax(self.fc(y[0]), dim=1)\n",
    "        return y, h, attn_w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T11:41:48.748873Z",
     "start_time": "2019-11-12T11:41:41.832570Z"
    }
   },
   "outputs": [],
   "source": [
    "lrate = 0.01\n",
    "epochs = 7\n",
    "teacher_forcing_ratio = 0.5\n",
    "hidden_size = 256\n",
    "\n",
    "enc = EncoderRNN(train_data.lang_in.n_words, hidden_size).cuda()\n",
    "dec = AttnDecoderRNN(hidden_size, train_data.lang_out.n_words, 1, dropout_prob=0.1).cuda()\n",
    "\n",
    "criterion = nn.NLLLoss()\n",
    "encoder_optim = torch.optim.SGD(enc.parameters(), lr = lrate)\n",
    "decoder_optim = torch.optim.SGD(dec.parameters(), lr = lrate)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意：每次反向传播的时候都需要将参数的梯度归零。  \n",
    "`optim.step()`则在每个`Variable`的`grad`都被计算出来后，更新每个`Variable`的数值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在每次训练中都用`train_loader`中的一个`batch`作为训练数据。  \n",
    "`Tensor.cuda()` 每个 `batch` 在实际使用之前，都先移入 `GPU` 后进行计算。  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T12:14:17.363307Z",
     "start_time": "2019-11-12T11:41:48.750926Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2m 5s (- 29m 46s) (5000 6%) 2.9022\n",
      "4m 8s (- 27m 19s) (10000 13%) 2.4035\n",
      "6m 13s (- 25m 19s) (15000 19%) 2.0836\n",
      "8m 21s (- 23m 23s) (20000 26%) 1.9025\n",
      "10m 29s (- 21m 23s) (25000 32%) 1.6633\n",
      "12m 38s (- 19m 22s) (30000 39%) 1.5298\n",
      "14m 48s (- 17m 20s) (35000 46%) 1.3878\n",
      "17m 0s (- 15m 17s) (40000 52%) 1.2490\n",
      "19m 10s (- 13m 11s) (45000 59%) 1.1571\n",
      "21m 20s (- 11m 5s) (50000 65%) 0.9769\n",
      "23m 32s (- 8m 58s) (55000 72%) 1.0032\n",
      "25m 39s (- 6m 49s) (60000 78%) 0.7996\n",
      "27m 46s (- 4m 41s) (65000 85%) 0.8351\n",
      "29m 54s (- 2m 33s) (70000 92%) 0.6273\n",
      "32m 3s (- 0m 24s) (75000 98%) 0.7002\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from plotting import timeSince, showPlot\n",
    "\n",
    "n_iters = epochs*train_data.len\n",
    "print_every = 5000\n",
    "plot_every = 500\n",
    "plot_loss_total = 0\n",
    "print_loss_total = 0\n",
    "plot_losses = []\n",
    "j = 0\n",
    "start = time.time()\n",
    "\n",
    "for e in range(epochs):\n",
    "    for (inputs, targets), _ in train_loader:\n",
    "        encoder_optim.zero_grad()\n",
    "        decoder_optim.zero_grad()\n",
    "        loss = 0\n",
    "        \n",
    "        inputs = inputs.view(-1, 1).cuda()\n",
    "        targets = targets.view(-1, 1).cuda()\n",
    "        dim_in = inputs.shape[0]\n",
    "        dim_out = targets.shape[0]\n",
    "        \n",
    "        enc_out = torch.zeros(MAX_LENGTH, enc.dim_hid).cuda()\n",
    "        enc_hid = enc.initHidden()\n",
    "        \n",
    "        for k in range(dim_in):\n",
    "            out, enc_hid = enc(inputs[k], enc_hid)\n",
    "            enc_out[k] = out[0][0]\n",
    "        \n",
    "        dec_in = torch.LongTensor([[SOS_token]]).cuda()\n",
    "        dec_hid = enc_hid\n",
    "        use_teacher_forcing = True if random.random() < teacher_forcing_ratio else False\n",
    "        \n",
    "        if use_teacher_forcing:\n",
    "            for k in range(dim_out):\n",
    "                out, dec_hid, _ = dec(dec_in, dec_hid, enc_out)\n",
    "                loss += criterion(out, targets[k])\n",
    "                dec_in = targets[k]\n",
    "        else:\n",
    "            for k in range(dim_out):\n",
    "                out, dec_hid, _ = dec(dec_in, dec_hid, enc_out)\n",
    "                top_v, top_i = out.data.topk(1)\n",
    "                ni = top_i[0][0]\n",
    "                dec_in = torch.LongTensor([[ni]]).cuda()\n",
    "                loss += criterion(out, targets[k])\n",
    "                if ni == EOS_token:\n",
    "                    break\n",
    "        \n",
    "        loss.backward()\n",
    "        encoder_optim.step()\n",
    "        decoder_optim.step()\n",
    "        \n",
    "        loss = loss.data / dim_out\n",
    "        \n",
    "        print_loss_total += loss\n",
    "        plot_loss_total += loss\n",
    "\n",
    "        j = j + 1\n",
    "        if j % print_every == 0:\n",
    "            print_loss_avg = print_loss_total / print_every\n",
    "            print_loss_total = 0\n",
    "            print('%s (%d %d%%) %.4f' % (timeSince(start, j / n_iters),\n",
    "                                         j, j / n_iters * 100, print_loss_avg))\n",
    "\n",
    "        if j % plot_every == 0:\n",
    "            plot_loss_avg = plot_loss_total / plot_every\n",
    "            plot_losses.append(plot_loss_avg)\n",
    "            plot_loss_total = 0\n",
    "\n",
    "showPlot(plot_losses)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T12:14:17.377973Z",
     "start_time": "2019-11-12T12:14:17.365955Z"
    }
   },
   "outputs": [],
   "source": [
    "def evaluate(encoder, decoder, sentence, max_length=MAX_LENGTH):\n",
    "    inputs = train_data.varFromSentence(train_data.lang_in, sentence).cuda()\n",
    "    dim_in = inputs.shape[0]\n",
    "\n",
    "    enc_hid = encoder.initHidden()\n",
    "    enc_out = torch.zeros(max_length, encoder.dim_hid).cuda()\n",
    "\n",
    "    for k in range(dim_in):\n",
    "        out, enc_hid = encoder(inputs[k], enc_hid)\n",
    "        enc_out[k] = enc_out[k] + out[0][0]\n",
    "\n",
    "    dec_in = torch.LongTensor([[SOS_token]]).cuda()  # SOS\n",
    "    dec_hid = enc_hid\n",
    "\n",
    "    decoded_words = []\n",
    "    decoder_attentions = torch.zeros(max_length, max_length)\n",
    "\n",
    "    for di in range(max_length):\n",
    "        out, dec_hid, dec_att = decoder(dec_in, dec_hid, enc_out)\n",
    "        decoder_attentions[di] = dec_att.data\n",
    "        top_v, top_i = out.data.topk(1)\n",
    "        ni = top_i[0][0]\n",
    "        dec_in = torch.LongTensor([[ni]]).cuda()\n",
    "        if ni == EOS_token:\n",
    "            decoded_words.append('<EOS>')\n",
    "            break\n",
    "        decoded_words.append(train_data.lang_out.index2word[ni.item()])\n",
    "    return decoded_words, decoder_attentions[:di + 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T12:14:17.613370Z",
     "start_time": "2019-11-12T12:14:17.379864Z"
    }
   },
   "outputs": [],
   "source": [
    "def showAttention(input_sentence, output_words, attentions):\n",
    "    print(attentions.shape)\n",
    "    # Set up figure with colorbar\n",
    "    fig = plt.figure()\n",
    "    ax = fig.add_subplot(111)\n",
    "    cax = ax.matshow(attentions.numpy(), cmap='bone')\n",
    "    fig.colorbar(cax)\n",
    "\n",
    "    # Set up axes\n",
    "    ax.set_xticklabels([''] + input_sentence.split(' ') + ['<EOS>'], rotation=90)\n",
    "    ax.set_yticklabels([''] + output_words)\n",
    "\n",
    "    # Show label at every tick\n",
    "    ax.xaxis.set_major_locator(ticker.MultipleLocator(1))\n",
    "    ax.yaxis.set_major_locator(ticker.MultipleLocator(1))\n",
    "\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "def evaluateAndShowAttention(input_sentence):\n",
    "    output_words, attentions = evaluate(enc, dec, input_sentence)\n",
    "    print('input =', input_sentence)\n",
    "    print('output =', ' '.join(output_words))\n",
    "    showAttention(input_sentence, output_words, attentions)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "select sentences from train dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T12:27:26.899092Z",
     "start_time": "2019-11-12T12:27:26.771329Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "> vous n etes pas encore mort .\n",
      "= you re not dead yet .\n",
      "< you re not dead yet . <EOS>\n",
      "\n",
      "> elle a peur des chats .\n",
      "= she is afraid of cats .\n",
      "< she is afraid of cats . <EOS>\n",
      "\n",
      "> je suis fatigue de ce temps chaud .\n",
      "= i m sick of this hot weather .\n",
      "< i m sick of this hot weather . <EOS>\n",
      "\n",
      "> nous avons vraiment peur .\n",
      "= we re really scared .\n",
      "< we re really scared . <EOS>\n",
      "\n",
      "> tu n es pas indispensable .\n",
      "= you re replaceable .\n",
      "< you re not . <EOS>\n",
      "\n",
      "> je vais sortir cet apres midi .\n",
      "= i m going to go out this afternoon .\n",
      "< i am going to go out out . <EOS>\n",
      "\n",
      "> nous n y sommes pas prets .\n",
      "= we re not ready for this .\n",
      "< we re not ready for this . <EOS>\n",
      "\n",
      "> ils ont des ennuis .\n",
      "= they re in trouble .\n",
      "< they re in trouble . <EOS>\n",
      "\n",
      "> il a des chances de remporter le jeu .\n",
      "= he is likely to win the game .\n",
      "< he is likely to win the game . <EOS>\n",
      "\n",
      "> elle travaille dur ce semestre .\n",
      "= she is working hard this semester .\n",
      "< she is working hard this work . <EOS>\n",
      "\n"
     ]
    }
   ],
   "source": [
    "for i, ((inputs, targets), (sen_in, sen_out)) in enumerate(train_loader):\n",
    "    if i > 9: break\n",
    "    sen_in = ''.join(sen_in)\n",
    "    sen_out = ''.join(sen_out)\n",
    "    print('>', sen_in)\n",
    "    print('=', sen_out)\n",
    "    outputs, attn = evaluate(enc, dec, sen_in)\n",
    "    sentence = ' '.join(outputs)\n",
    "    print('<', sentence)\n",
    "    print('')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "use new sentences"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T12:14:19.155050Z",
     "start_time": "2019-11-12T12:14:17.843405Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "input = je suis trop froid .\n",
      "output = i am too too . <EOS>\n",
      "torch.Size([6, 10])\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "input = elle a cinq ans de moins que moi .\n",
      "output = she s five years younger than me . <EOS>\n",
      "torch.Size([9, 10])\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAWIAAAEZCAYAAACtuS94AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAH1BJREFUeJzt3Xm4HVWd7vHvS0BAQByCrTIYsLExIBKIQRtUVOQGZXhUFFBui6KhVZzRi8NFBX1sRNumFZWIqNcZUTQX0wRRcAaSMCQQRHIZmogDQURAIeSc9/5RdcLO4Qz7JFW79vB+8tST2lW111p1svM7a69ag2wTERHN2aTpAkREDLoE4oiIhiUQR0Q0LIE4IqJhCcQREQ1LII6IaFgCcUREwxKIIyIalkAcEdGwBOKI6AgVvi/paU2XpdskEEdEpxwEzAZe33RBuk0CcUR0ynEUQfhQSZs2XZhukkAcEbWTNB3Y3faFwMXASxsuUldJII6ITvgX4Jvl/pcoasdRSiCOiE54LUUAxvZi4ImSdmy2SN0jgTj6nqT9JG1V7h8j6d8lPbnpcg0KSY8GPmP7dy2HTwSmN1SkrqNMDB/9TtIy4BnAnsBXgS8CL7P9vEYLFlFKjTgGwVoXNY7DgTNsnwFs03CZBoKkN0jatdyXpC9J+qukZZJmNV2+bpFAHIPgHknvBY4BfihpGrBZw2UaFG8Dbin3j6b4VrIz8E7gPxsqU9dJII5BcCTwAHCc7T8A2wOnN1ukgbHW9oPl/iHA/7F9p+2Lga0aLFdXSRtxRNRG0pXAS4C7gFuBF9i+rjx3ve0MdyY14hgAkl4m6UZJd5ftk/dI+mvT5RoQJwNLKJonFrQE4ecBNzVYrq6SGnH0PUkrgUNtX990WQZROZx5G9t3tRzbiiL+3NtcybpHxnvHIPhjgnCjHgu8WdLugIEVwGdt/7HZYnWP1Ih7nKS9Jzpv+8pOlaVbSToDeALwfYqHdgDY/l5jhRoQkvYDvgF8GVgKCNgbeA3watu/bK503SOBuMdJuozig72M4kP+dOAK4EHAtl/QYPG6gqQvjXHYtl/X8cIMmPLz+UbbV406vhdwlu19mylZd0nTRO+7BXiD7eUAkvYATrR9bJOF6ia2X1t3HuWQ6V1tXyxpS2BT2/fUnW8PeNToIAxg+2pJGVRTSiAGJO1P8Z/oS5K2A7a2fXPT5WrTbiNBGMD2tWVtoxaSHgPsaHtZXXlURdJ7bH9c0qcp2ibXY/utFeXzBmAeRVvoU4AdgM8DL6wg7Y7cQ40k6TGtD+rKg48lvbbWGfhALOmDFKsG/BPF7FCbAV8D9muyXFNwvaSzKcpsitFjlT6YknQpcBjF5+Vq4A5JP7X9zirzqcHIz2FJzfm8GZgDXA5g+0ZJj68o7U7dQ10+BVwk6URg5HnFPsBp5bkgbcRIuhqYBVxpe1Z5bJntPZstWXskbQG8EXhueehnwOds319hHlfZniXp9RS14Q/20s9oRPlV2FV3mZJ0ue19W35Om1J8nir/+dR1D3WSdAjwHqC118Tptv9vowXrIgNfIwbW2LYkw7r+jT2jDLifot7axaaSngi8Enh/jfnUomw3/ypF04Ek3QH8y8jgggr8VNL7gC0lvQh4E1BpkOnAPdTG9gXABU2Xo5uljQbOlXQW8Oiyre9i4AsNl6lt5Vy7P5L0W0k3jWwVZ3MKsAhYaXuxpF2AGyvOo07zgXfafrLtnYB3Ue2/8UnAHcBy4HhgIfCBCtOH+u+hFpLObdk/bdS5izpfou408E0TAGUt5iCK7l+LbP+o4SK1TdJvgHdQ9NEcGjlu+87GCtVlJF1j+xmTHetmvXoPI8015f6Vtvce69ygS9MEUAbengm+o9xt+7/qzKDsSfIGYAYtn5mq+uFKeirwOeAfbO8haU/gMNsfqSJ94CZJ/5viqz0UDzQr6xUj6WbG7tGwS1V5UPM91Giiml5qgaWBDcSS7mHsD4IoHoY8qsNF2lCXSDod+B7rjxqrckTdD4CfUzTbDE1y7Yb4AvBu4CwA28skfQOoKhC/Dvgw8F2Kf9+fAcdWlDYUvW5GbAG8gqItt0p130NdHllOAL8JRRv6LIryC9iy0ZJ1kTRN9DhJl4xxuNIRdZKutl1n3+TFtp856mtsZXlKmk3xkHEGD1U+XGevD0m/sL1/hel1/B6qMM7ncx3bz+9UWbrZINeIJ6yx2P5zp8qyMTr0Qb5A0ottL6wp/dWSnkL5DUXSEcDvK0z/6xSLVV4LDFeYLvCw+T42oaghVz1qrNZ7qEsCbXsGtkbc0q4nHmqiUPm3K27fq5ykY2x/TdKYgyps/3uFed1DsZrCAxRzWFTafFP2wpgP/DPFBOI3U0wIc2tF6VdaOx0j/Ut46DO0lmLY+Sds/7bCPGq9hzqVQ76favualmM7AUOjVnYeWANbI7a9M4CkTYBXAzvbPqX8gDyxyrzKYcG7UrQfjuT/s41MdqS/81g1r0p/u9repvwGsd49bKxRv0QWApdQ1CjvA14OVPXL5IPl6MMfU8/saxfw0C91yv1DJI3kU8V91H0PdVoLfE/SnrbvK4+dDbwPSCBmgANxizMpvuq9gKK/7D0UD0SeWUXi5Wi0t1HMP3A18Czg12V+G8z2WeXuLsDbbP+lzO8xwCc3Ju3RxrmHX7HxcymM/BL5J4qf9w8ogtn/pHgYVZXXArtRDF8f+VpvigecVdiH9ct/KEX5b6sofaj/Hmpj+0FJ51OsHXhOWdnZznavDtuunu2B3iiGogJc1XLsmgrTX05Ri7y6fL0b8O0K07+qnWNdfg8XUazgMPJ6G+DCKstf82eo1vJ34h7q3srPzM/L/Q8Ab226TN20ZWQdPKhiefWRB0XbUe3DkPtdzvsgaXPbv6GoAVZlk7IWTJnHY6n+m07d97ATsKbl9RqK3gFVuUzSzArTG63u8kP991Cr8jMz0mf8aB7qDx2kaQLgP4HzgcdL+ihwBNUOT10l6dEUq0P8SNJdwO0Vpv9J4FeSzqP4ZfJK4KMVpg/138NXgSvKr68GXgp8pcL09wdeUz6gfYCHHjZW1fWr7vJD/ffwMJKeYPsPFSb5RYq24WUeNS3moBvYXhOtJO1G0d4p4MeuaX0zFSvXbkvxtXXNZNdPId2ZFG3OI+VfUVXaY+RV1z3sDTynfPkzjzGZ+Eak/eSxjruiXhllHrWVv0y/9nsYI88f2n5Jhek9kqJb4sttX1xVuv0ggTgiomFpI46IaFgC8SiS5iX9pN+t6Xcij15PvxclED9c3R+SpJ/0uz2PXk+/5yQQR0Q0rK8f1k2fPt0zZsyY0nvuuOMOtttuu7auXbp06QaUKiKmaLXt9v5TjmPu3LlevXp1W9cuXbp0ke25G5PfVPV1P+IZM2awZEl9oyhH5hKIiFptdBe91atXtx0LJE3f2Pymqq8DcUTEiG7+9p9AHBF9z8DQcPdO45xAHBEDwLiLl8hLII6I/mcY7t44nEAcEYMhbcQREQ0yMJxAHBHRrNSIp0DSLcBs2+31vo6ImITt9JqIiGhaN9eIG51rQtJWkn4o6RpJ10o6sjz1FklXSlpeTto+cu05khZLukrS4Q0WPSJ6jNv804SmJ/2ZC9xu+xm29wAuLI+vtr038DngxPLY+4Gf2H4m8HzgdElbjU5Q0jxJSyQtueOOOzpwCxHR7YqHde1tTWg6EC8HDpR0mqTn2L67PD6yRPhSHlqE8SDgJElXA5dSrCq80+gEbc+3Pdv27HYn74mI/jeFFac7rtE2Ytu/lbQP8GLgY5IuKk89UP49xENlFMVaVzd0uJgR0eu6/GFd023ETwL+ZvtrwCeAvSe4fBFF27HK987qQBEjog+Y1Ign8nSKtt5h4EHgjcB541x7KvAfwLIyGN8CHNKJQkZE78uAjnHYXkRR0201o+X8EuCAcv/vwPGdKltE9Jdu7r7WdI04IqIDMvtaRESjnNnXIiKaN9zFvSYSiCOi72X2tYiILpCHdRERTbJTI27K0qVLe3rJ+078Bu/ln0/EVKRGHBHRIANDCcQREc1KjTgiomEJxBERDXIe1kVENC814oiIhiUQR0Q0qOg1kSHOERGNyqQ/ERFNanD1jXYkEEdE3xtZKqlbNb2K85RJ2krSDyVdI+laSUc2XaaI6H7DZRe2ybYm9GKNeC5wu+2XAEjatuHyREQPSI24WsuBAyWdJuk5tu9uPSlpnqQlkpY0VL6I6DK2GRoebmtrQs8FYtu/BfahCMgfk3TyqPPzbc+2PbuRAkZEV3Kbf5rQc00Tkp4E/Nn21yTdCxzbcJEiogd0c/e1nqsRA08HrpB0NfB+4CMNlyciutxIr4l2tslImivpBkkrJZ00xvmdJF0i6SpJyyS9eLI0e65GbHsRsKjpckREb6niYZ2kacCZwIuAVcBiSQtsr2i57APAubY/J2kmsBCYMVG6PReIIyKmrHxYV4E5wErbNwFI+hZwONAaiA08qtzfFrh9skQTiCOi71U4oGN74LaW16uAfUdd8yHgIklvAbYCDpws0V5sI46ImLIpDOiYPtIFttzmtSQz1iKPoyP80cCXbe8AvBj4qqQJY21qxBExEKbQNW31BN1fVwE7trzegYc3PRxHMfAM27+WtAUwHfjTeBmmRhwRA8Fub5vEYmBXSTtLegRwFLBg1DX/DbwQQNLTgC2AOyZKNDXiiOh7hkrmkbC9VtIJFD23pgHn2L5O0inAEtsLgHcBX5D0jjLrYz1JA3UCcReTxmqOqlbd4+87cQ8Rk6qu1wS2F1J0SWs9dnLL/gpgv6mkmUAcEX2v26fBTCCOiIGQQBwR0bCm5hpuRwJxRAyA5mZWa0cCcUT0vTa7pjUmgTgiBkJTk763I4E4IvpeVf2I65JAHBEDoZt7TTQ6xFnSWyVdL+musSZYjoioRJuTwjcVrJuuEb8JONj2zQ2XIyL6XWrEDyfp88AuwAJJ75D0GUnbSrplZMo4SY+UdJukzSQ9RdKFkpZK+rmk3Zoqe0T0nuEht7U1obFAbPtfKaaPez5wV3nsbuAa4HnlZYcCi2w/CMwH3mJ7H+BE4LMdL3RE9KSi+1qaJqbi28CRwCUUU8x9VtLWwD8D32mZRGbzsd5cTuI8b6xzETG4uvlhXTcG4gXAxyQ9FtgH+AnFciN/sb3XZG+2PZ+i9oyk7v3JR0QHNVfbbUfXTQxv+17gCuAM4ALbQ7b/Ctws6RUAKjyjyXJGRG/xsNvamtB1gbj0beCY8u8RrwaOk3QNcB3FyqkREZNKG/EEbM8od79cbiPHz2PUIn1lF7e5HSpaRPQZZ4hzRESzuriJOIE4IgaAm2v/bUcCcUQMhG7uNZFAHBF9L2vWRUR0gQTiiIgm2XgovSYiIhqVGnF0rZa5O2pR94e/7vJH/+jiOJxAHBH9Lw/rIiKa5gTiiIiGmeE8rIuIaFZqxBERDXKaJiIiukACcUREs9y9TcQJxBExGNI0ERHRJJvhTAy/8SRNsz3UdDkiovd0+4COWtask3SqpLe1vP6opLdKerekxZKWSfpwy/nvS1oq6TpJ81qO3yvpFEmXA8+W9G+SVpTv/0QdZY+IPuTqFg+VNFfSDZJWSjppnGteWcaq6yR9Y7I061o89IvAa8oCbQIcBfwR2BWYA+wF7CPpueX1r7O9DzAbeKukx5XHtwKutb0vsAJ4KbC77T2Bj4yVsaR5kpZIWlLPrUVETyr6sE2+TUDSNOBM4GBgJnC0pJmjrtkVeC+wn+3dgbdPVrRaArHtW4A7Jc0CDgKuAp7Zsn8lsBtFYIYi+F4DXAbs2HJ8CPhuuf9X4H7gbEkvA/42Tt7zbc+2Pbvq+4qIXtXeCs5tNF/MAVbavsn2GuBbPHxF+TcAZ9q+C8D2nyZLtM424rOBY4EnAOcALwQ+Zvus1oskHQAcCDzb9t8kXQpsUZ6+f6Rd2PZaSXPKdI4CTgBeUGP5I6KPDLe/Zt30Ud+o59ueX+5vD9zWcm4VsO+o9z8VQNIvgWnAh2xfOFGGdQbi84FTgM2AVwFrgVMlfd32vZK2Bx4EtgXuKoPwbsCzxkpM0tbAI20vlHQZsLLGskdEH3HZRtym1RN8ox5r3tXRCW9K8a3+AGAH4OeS9rD9l/EyrC0Q214j6RLgL2Wt9iJJTwN+Xc4hey9wDHAh8K+SlgE3UDRPjGUb4AeStqD4YbyjrrJHRP+pqNfEKorm0xE7ALePcc1lth8EbpZ0A0VgXjxeorUF4vIh3bOAV4wcs30GcMYYlx88Vhq2t27Z/z1F+0xExJRVFIgXA7tK2hn4HUUz6atGXfN94Gjgy5KmUzRV3DRRonV1X5tJ0XTwY9s31pFHRET7qnlYZ3stxfOpRcD1wLm2ryu72R5WXraIorPCCuAS4N2275wo3VpqxLZXALvUkXZExJRVOPua7YXAwlHHTm7ZN/DOcmtLz4ysi4jYUAY81L0j6xKII2IgdPMQ5wTiiOh/7Q3WaEwCcUQMhCn0I+64BOKoVdlnvDZ113LqLn90TmrEEREN6vZpMBOII6L/2TgTw0dENCtr1kVENCxNExERTapwZF0dEogjou/lYV1EROPM8FD3NhInEEdE/0vTREREF0ggroekaSNr2kVETKSL4/DEE8NLOlXS21pef1TS2ySdLulaScslHVmeO0DSBS3XfkbSseX+LZI+LOnK8j27lce3k/Sj8vhZkm4tZ7RH0jGSrpB0dXluWnn83nIS5suBZ1f9A4mI/jPysK6CVZxrMdkKHV8EXgPrlj46imI9pr2AZ1Csvny6pCe2kddq23sDnwNOLI99EPhJefx8YKcyr6cBRwL72d4LGAJeXb5nK+Ba2/va/sXoTCTNk7Rk1CqsETHIysVD29maMGHThO1bJN0paRbwD8BVwP7AN8smgT9K+inwTOCvk+T1vfLvpcDLyv39gZeWeV0o6a7y+AuBfYDF5aQrWwJ/Ks8NAd+doMzzgfkAkrr4y0hEdI4Z7vEhzmcDxwJPAM4BDhrnurWsX8PeYtT5B8q/h1ryHW9qKwFfsf3eMc7dn3bhiJiqbu410c7ioecDcylqvYuAnwFHSpomaTvgucAVwK3ATEmbS9qWolY7mV8ArwSQdBDwmPL4j4EjJD2+PPdYSU9u/7YiIkax29saMGmN2PYaSZcAf7E9JOl8iodk11C0gb/H9h8AJJ0LLANupGjGmMyHgW+WD/x+CvweuMf2akkfAC4q26YfBN5MEewjIqbE7vGJ4ctA+CzgFbBuhdJ3l9t6bL8HeM8Yx2e07C8BDihf3g38D9trJT0beL7tB8rrvg18e4y0tp6szBERo3Vxy8TEgVjSTOAC4HzbN9aQ/07AuWWwXwO8oYY8ImLg9fCadbZXALvUlXkZ3GfVlX5EBACm53tNRET0NNPjbcQREf2gZ5smIiL6Q3Nd09qRQBwR/S/TYEbUZ7PNNq81/Zkz96s1/dO+9ula0wc4dO+9a8+jFwwPJRBHRDQmSyVFRDQtTRMREU3r4QEdERH9IoE4IqJh3Tygo51pMCMietrI7GtVrNAhaa6kGyStlHTSBNcdIcmSZk+WZgJxRAyEKtasK9fOPBM4GJgJHF1Ojjb6um2AtwKXt1O2BOKIGADtBeE22pHnACtt32R7DfAt4PAxrjsV+Dhwfzul61gglvRoSW8q99db8TkiolbVNU1sD9zW8npVeWydco3PHW23HeM6WSN+NPCmDuYXEbHOFGrE00dWgi+3eS3JjLXO5rroXc6t/ingXVMpWyd7Tfwb8BRJV1MsfXSfpPOAPShWdj7GtiWdDBxKsXLzr4Djy+OXUrS3PJ8iqB9n++cdLH9E9KgpjqxbbXu8B2yrgB1bXu8A3N7yehuKmHZpuQL9E4AFkg4rVycaUydrxCcB/8/2XhTLLM0C3k7R4L0LMDKo/zO2n2l7D4pgfEhLGpvanlO+74NjZSJp3shvspruIyJ6jvHwcFvbJBYDu0raWdIjgKOABetyse+2Pd32jHKJuMuACYMwNPuw7grbq2wPA1cDM8rjz5d0uaTlwAuA3Vve873y76Ut16/H9nzbsyf4jRYRg8bg4fa2CZOx1wInUKxofz1wru3rJJ0i6bANLV6TAzoeaNkfAjaVtAXwWWC27dskfQjYYoz3DJHBKBExBVWNrLO9EFg46tjJ41x7QDtpdrJGfA9F+8lERoLuaklbA0fUW6SIGBQVdV+rRcdqlbbvlPRLSdcCfwf+OMY1f5H0BWA5cAtFe0xExEbJNJgtbL9qnOMntOx/APjAGNcc0LK/mnHaiCMiHsZmeCirOEdENCs14oiIZpkE4oiIxjgrdERENM14sk7CDUogjoiBkBpxRETDhicfvtyYBOLoaWvXrqk1/RUrfllr+ofMmlVr+lEoBmskEEdENCtNExERzUr3tYiIhuVhXUREo8zw8FDThRhXAnFE9L0M6IiI6AIJxBERDUsgjoholNN9LSKiaSYDOiIiGmN39xDnJldxXo+kGZJ+I+lsSddK+rqkA8vllW6UNEfSVpLOkbRY0lWSDm+63BHRC9pbr67v16xr0z8CrwDmUaxX9ypgf+Aw4H3ACuAntl8n6dHAFZIutn3fSAKS5pXvj4hYJ3NNtO9m28sBJF0H/Ni2JS2nWKNuB+AwSSeW128B7ARcP5KA7fnA/DKN7m2dj4iOSq+J9j3Qsj/c8nqYoqxDwMtt39DpgkVEb+vmQNw1bcRtWgS8RZIAJGUOwYiYnN3+1oBuqxFP5lTgP4BlZTC+BTik0RJFRNczMOzMNTEp27cAe7S8Pnacc8d3slwR0Q+a6xHRjq4JxBERdUogjohoWAJxRESDiudw6UccEdEg4y4e4pxAHBEDIWvWRUQ0LG3EERGNctqIIyKa1O1r1vXaEOeIiA1S1TSYkuZKukHSSkknjXH+nZJWSFom6ceSnjxZmgnEETEQhoeH29omImkacCZwMDATOFrSzFGXXQXMtr0ncB7w8cnKlkAcEQPA4OH2tonNAVbavsn2GuBbwHoLVNi+xPbfypeXUUzfO6EE4ogYCG7zDzBd0pKWrXWhie2B21peryqPjec44L8mK1se1kVE35viw7rVtmePc05jJT/mhdIxwGzgeZNlmEAcEQOhol4Tq4AdW17vANw++iJJBwLvB55n+4HR50dLII6IAVBZP+LFwK6SdgZ+BxxFsbbmOuWCFWcBc23/qZ1EE4gjYiBM1iOiHbbXSjqBYrWgacA5tq+TdAqwxPYC4HRga+A75WJC/237sInSTSCOiL5X5YAO2wuBhaOOndyyf+BU00wgjogB0Nx6dO1III6IgWAy10THlH3+5k16YUQMlG6ea6LvArHt+cB8AEnd+5OPiA5yJQ/r6tJ3gTgiYrRuXyqpZ4c4S1oo6UlNlyMiekNVs6/VoWdrxLZf3HQZIqJ3pI04IqJR6b4WEdG4LB4aEdEgG4aHh5ouxrgSiCNiADT3IK4dCcQRMRASiCMiGpZAHBHRsG4e0JFAHBH9z+m+FhHRKAPDqRFHRDQrTRMREY1K97WIiMYlEEdENKjKNevqkEAcEQPAOEOcIyKa1c2T/tQyMbykSyXdIOnqcjuv5dw8Sb8ptysk7d9y7hBJV0m6RtIKScfXUb6IGDwDMTG8pEcAm9m+rzz0attLRl1zCHA8sL/t1ZL2Br4vaQ5wJ8Vac3Nsr5K0OTCjfN9jbN9VVVkjYvB0cxvxRteIJT1N0ieBG4CnTnL5/wLebXs1gO0rga8Abwa2ofjFcGd57gHbN5TvO1LStZJOlLTdxpY5IgZLUdsdbmtrwgYFYklbSXqtpF8AZwPXA3vavqrlsq+3NE2cXh7bHVg6KrklwO62/wwsAG6V9E1Jr5a0CYDtzwMHA1sCP5N0nqS5I+cjIibTj00TvweWAa+3/ZtxrnlY08Q4RDECEduvl/R04EDgROBFwLHluduAUyV9BJgLfJEiqB+2XmLSPGDeVG8oIvrb8HD3jqzb0BrlEcDvgPMlnSzpyW2+bwWwz6hje5fHAbC93PanKILwy1svLNuSPwt8GvgO8N7RGdieb3u27dnt3kxEDICRiX8m2xqwQYHY9kW2jwT2B+4GfiDpYkkzJnnrx4HTJD0OQNJeFDXez0raWtIBLdfuBdxaXneQpGXAR4BLgZm23277ug0pf0QMGmOG29qasFG9JmzfCZwBnFHWVlt7TH9d0t/L/dW2D7S9QNL2wK8kGbgHOMb27yVtA7xH0lnA34H7KJslKB7gHWr71o0pb0QMpm4fWaduLtzGKoN9RNfqxP8/SbXnUbOlG9vUuMkm07z55lu2de3999+30flNVUbWRcRA6OZKZwJxRAwAM5y5JiIimtPtbcQZEBERg6Gi7mvlYLIbJK2UdNIY5zeX9O3y/OVt9CZLII6IQeC2/0xE0jTgTIqRvjOBoyXNHHXZccBdtv8R+BRw2mSlSyCOiIFQ0VwTc4CVtm+yvQb4FnD4qGsOp5hDB+A84IWapOtK2ogjYiBUNMR5e+C2ltergH3Hu8b2Wkl3A48DVo+XaL8H4tWUo/OmYDoT/MAqkPST/job2Me3q+6hA+m3O4XCRBaV+bZjC0mt8+TMtz2/3B/rH2x0e0Y716ynrwOx7SlPmSlpSZ2duZN+0u/2PHo9/bHYnltRUquAHVte7wDcPs41qyRtCmwL/HmiRNNGHBHRvsXArpJ2LhfDOIpi+t5WC4DXlPtHAD/xJH3n+rpGHBFRpbLN9wSKpo5pwDm2r5N0CrDE9gKKKXq/KmklRU34qMnSTSB+uPmTX5L0k35j6Xcij15Pv1a2FwILRx07uWX/fuAVU0mzryf9iYjoBWkjjohoWAJxRETDEogjIhqWQBwR0bAE4oiIhiUQR0Q0LIE4IqJh/x8rJUD4pwNqUgAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "input = elle est trop petit .\n",
      "output = she is too short . <EOS>\n",
      "torch.Size([6, 10])\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "input = je ne crains pas de mourir .\n",
      "output = i m not scared to die . <EOS>\n",
      "torch.Size([8, 10])\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXgAAAEYCAYAAABWae38AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAHDJJREFUeJzt3XuYXFWd7vHvS0CJGrkY5oxcw1FAAyKQAF5wxBF9IiroEbmIjjhqnBl1juOg4uWgw+DjIDheQWk94GW8IHjQDDID6hFxVISEO4GMOSASYNQgBkTkknrPH3s3FkV3V3d1Ve1du98PTz3Zt1prVYf8etXaa/+WbBMREc2zSdUNiIiIwUiAj4hoqAT4iIiGSoCPiGioBPiIiIZKgI+IaKgE+IiIhkqAj4hoqAT4iIiGSoCPmANU+Kakp1bdlhieBPiIueGFwFLgDVU3JIYnAT6Ch3q4O1TdjgF6PUVwf6mkTatuTAxHAnwE4CLr3jerbscgSFoI7G7734HvAi+vuEkxJAnwEX90iaR9q27EAPwF8NVy+0yK3nzMAUq64IiCpNXArsDNwD2AKDr3e1basFmSdA2wzPat5f5VwEts31Jty2LQMhbXEJJeCfy77bslvQ/YBzjR9uUVN22UvKjqBvSbpC2BT40H99KxwEIgAb7h0oNvCElX295T0gHAh4BTgPfY3r/iptWepMfbvkvS1hOdt/2bYbcpoh8yBt8cG8s/Xwx82va3gEdV2J5R8pXyz1XAyvLPVW37I0nSGyXtUm5L0pmS7pJ0taS9q25fDF568A0h6TzgVuAgYAlwL3Cp7adX2rARIUnADrZ/UXVb+kXStcDeth+Q9Crg7ynmw+8NvN/2cyptYAxcevDNcThwAcXNtN8CWwPvqLZJo6OcJnlu1e3oswdtP1BuvwT4ou07bH8XeGyF7YohSYBvCNu/B74F3CNpR2Az4IZqWzVymjZNsiXpiZI2B55PMQd+3PyK2hRDlFk0DSHprcD7gV8CrfKwgZGe4jdkzwPeJKkp0ySPp7iHMA9YYfs6AEnPBW6ssmExHBmDbwhJa4H9bd9RdVtGlaSdJjpu++Zht6VfyrQEC2zf2XbssRT/9n9XXctiGNKDb45bgA1VN2LENbG3szXwZkm7U3y+1cBptn9ZbbNiGBLgm+NG4CJJ3wbuGz9o+5+ra9LI+TZFEBSwObAzsAbYvcpG9UrSsymmgH4e+CLF59oH+Kmko23/qMLmxRAkwDfHL8rXo8j8957Yflr7vqR9gDdV1Jx++AjwMttXtB37lqRzgdOBPATXcBmDj5iCpMtt71N1O3ohabXtxTM9F82RHvyIk/Qx22+T9K9MMIZs+5AhtGET4HG27xp0XYMk6e1tu5tQDGf8uqLm9IMkbdV+g7U8uDWZIj0nJMCPvi+Vf54yzEolfQX4K4oUCauALST9s+2Th9mOPlvQtv0gxZj8NypqSz98FLhQ0rHAeNK5JcBJ5blouAzRRE8kXWl7L0lHUwSNdwGrRnjO+EMkLaCY/z7y0wglvQR4J8WN4vFZNCfb/tdKGxZDkR58Q5RJpT4ELKaYAQKA7f8+oCo3k7QZ8DKKdLQPSBrp3oKkPSi+EW1d7q8HXmv72kobNgu2zwPOq7odUY2MwzXHmcCnKYYWnkcxLe5LU75jdk4Hfk6R0+Ti8iGhkR6DB8aAt9veyfZOFMm5xipuU88kfb1t+6SOcxcOv0UxbBmiaQhJq2wvkXTN+HQ/ST8cZsZASZvafnBY9fWbpKs6s29OdGxUSLrC9t7l9sNmA7Wfi+bKEM2ASdqVomf932zvIWlP4BDbJ/a5qj+Us1l+JuktFKmD/6TPdTyMpBdTjO1u3nb4hD7XMayfH8CNkv4Xf/zm82rgpgHUMyxT9d7Ss5sDMkQzeJ8F3g08AGD7auDIAdTzNuAxwN9S3PR8NfDaAdQDgKTPAEcAb6V4QvKVwIS5XGZpWD8/gL8EtqGYOfN/KJa1O2ZAdQ3DYyTtLWkJML/c3md8v+rGxeDNyR58uazdLrbPlLQNxRzuQfXUHmP70mI9iYf0dRhD0jzgcNvvAH4HvK6f5U/iWeUSgVfb/gdJH6EIiv028J9fmycBO1B0fDalSLH754xuRs7bgfFUFf/Vtj2+Hw035wK8pPcDS4HdKG5Mbgb8C/DsAVW5XtKTKL8SSzqM4h9e39jeKGmJJHl4N1XuLf/8vaRtgTsocrf028B/fm2+TLEg9bX8MeXyyLL9vKrbENWacwEeeDnFkmWXA9i+rZz3PChvppiJ8RRJt1KM6R49gHquoMgzcjZFLnMAbA+iVw1wnqQtgQ9TPOgE8LkB1DOsnx/Ar5s2P1zSfGBX21e1HdsR2Gj71upaFsMw52bRSLrU9n7jswrK3Ng/GdQDOpIeDRwGLKKYX30XxUM0/b4ZeeYEh237L/tZT1t984G/Bp5D0bv+IcVi33/oU/lv7zg0n2Lo5B4YTJZMSc8HjgK+x8Mzcg7ql+TAlc8q3ADsafue8tiFwHtsj+yC4jE9c7EH/3VJpwNbSnoj8HoG0/Mc9y3gtxTfGG4bYD2bAP+zXI8VSVtRZBMclC8AdwOfKPePoph7f3ifyh//VrUbsC/Fz1HAa4CL+1RHp9cBT6EYtmtfFWtkA3z5ANq5FDfEzyh779skuM8Nc64HDyDpBRSrywNcUC5CPKi6rrW9x6DKb6vnEfOaBznXeVhzxsve5its313uLwDOtr2sn/WUZT/0DEGTSHoK8Fnbz5H0PuAu25/o9r4YfXNmmqSk/yj/vJtiGtxfla9zJW2QdJOkvxlA1T+WNIygsUnZawceyhg4yG9oV0h6Rlt9+wODWEBiR+D+tv37KYa7BuESSY1LoWv7BnjomYKjGOwTzlEjc7IHPxFJTwB+bHu3Ppe7Gngyxc3B+xjQQs6S/oJivvg5FMMKhwMftD2Qf8ySrqcYPvlFeWhH4HqKoY2+fT5J76X4LOdSfK6XA2fZ/lA/yu+o63qKqZID/buaov4/tT2Q6YuSjqGY53+r7aMGUUfUTwJ8G0lPtN3XKXga4kLOZe/zzykC0/dsr+53HW11TflQUz8/X7my0njKhYs7Vijqm2H+XU1S/7dtv3hAZT+GYnrpKwY5JBn1kgAfEdFQc2YMPiJirkmAj4hoqDkf4CUtT12jUVcTP1PqGp16RtGcH4OXtNL20tRV/7qa+JlS1+jUM5Fly5Z5/fr1Xa9btWrVBYN4dqObufgka0REX6xfv56VK7s/FCxp4RCa8wiNCvALFy70okWLZvSeHXfckaVLl874a8yqVau6XzQBDXHd0ibW1cTPlLoqq2e97W1mW3edR0EaFeAXLVo0rd+m/dCRnzwiRs+sn28wsLFV38zSjQrwERHDZVzj1Q8T4CMiemVo1Te+J8BHRMxGxuAjIhrIQCsBPiKimdKDj4hoINuZRRMR0VR17sGPTC4aST+uug0REZ08jf+qMjI9eNvPqroNERHtipusVbdiciMT4CX9zvbjqm5HRES7Og/RjEyAj4iondxkHawyF/RyKBKHRUQMi6l3D35kbrJOxvaY7aW2l26zzawTw0VEzEjL7vqqysj34CMiqlTnHnwCfEREz5JNsi8ygyYi6sbJJhkR0VytzKKJiGieZJOMiGiw3GSNiGiiiqdBdpMAHxExC+nBR0Q0kIGNCfAREc2UHnxEREMlwA/JqlWrkFR1M0bWMP9Hzd9TNIFzkzUiornSg4+IaKgE+IiIBipm0SRVQUREIyXZWEREE9kZoomIaKK6L9mXAB8RMQuZJhkR0VDpwUdENJBtNmbBj4iIZsqarBERDVXnaZKbVN2AdpIWSbpB0uckXSvpy5IOkvQjST+TtF/VbYyIGDc+i6bbazokLZO0RtJaScdNcH5HSd+XdIWkqyUd3K3MWgX40pOBjwN7Ak8BXgUcABwLvKfCdkVEPEI/ArykecCpwIuAxcBRkhZ3XPY+4Ou29waOBE7rVm4dh2husn0NgKTrgO/ZtqRrgEWdF0taDiwfbhMjIoD+3WTdD1hr+0YASV8DDgVWt9cGPL7c3gK4rVuhdQzw97Vtt9r2W0zQXttjwBiApBqPhkVE0/TxQaftgFva9tcB+3dc8wHgQklvBR4LHNSt0DoO0UREjIxWmRN+qhewUNLKtlfnqMNECyR0/uY4Cvi87e2Bg4EvSZoyhtexBx8RMTKmOU1yve2lU5xfB+zQtr89jxyCeT2wDMD2TyRtDiwEfjVZobXqwdv+ue092vaPsX3OROciIurA7v6ahsuAXSTtLOlRFDdRV3Rc8wvg+QCSngpsDvx6qkLTg4+I6JHpTy4a2w9KegtwATAPOMP2dZJOAFbaXgH8PfBZSX9XVn2Mu9wASICPiOhVH1MV2D4fOL/j2PFt26uBZ8+kzAT4iIgeJV1wRESDJcBHRDRU8sFHRDSSk00yIqKJZjANshIJ8BERs5AFP2JWhnUTR5roaemImEy/5sEPSgJ8RMQsZBZNREQTzWBBjyokwEdEzEYCfEREM7U2JsBHRDROMU0yAT4iopES4CMiGik3WSMiGsutBPiIiMap+xh8rZbsm4ykYyRtW3U7IiI6udXq+qrKSAR44BggAT4iaqdPa7IORCUBXtIiSddL+qyk6yRdKGm+pL0kXSLpaknnStpK0mHAUuDLkq6UNL+KNkdEPIKNW91fVamyB78LcKrt3YHfAq8Avgi8y/aewDXA+22fA6wEjra9l+17K2txREQHl+kKpnpVpcqbrDfZvrLcXgU8CdjS9g/KY18Azu5WiKTlwPLBNDEiYnJZk3Vy97VtbwS27KUQ22PAGICk+v6kI6KR6hzg63STdQNwp6TnlPuvAcZ783cDCyppVUTEZGy8sdX1VZW6zYN/LfAZSY8BbgReVx7/fHn8XuCZGYePiLqocw++kgBv++fAHm37p7SdfsYE138D+MbgWxYRMTM1ju+168FHRIyM3GSNiGiqmqcqSICPiOiZaVV4E7WbBPiIiFlIDz4iooHqnk0yAT4iYjYS4CMimsn1HYJPgI+ImI0M0cSsSKq6CX03zH8UTfz5RU3YtCpc0KObOuWiiYgYKeMPOvUjXbCkZZLWSFor6bhJrjlc0upyHY2vdCszPfiIiF65P4tuS5oHnAq8AFgHXCZphe3VbdfsArwbeLbtOyX9Sbdy04OPiJiN/qzZtx+w1vaNtu8HvgYc2nHNGykWSbqzqNa/6lZoAnxERM+6D89Mc4hmO+CWtv115bF2uwK7SvpRubTpsm6FZogmImIWWtMbolkoaWXb/li5WNG4iWYCdBa8KcVSpwcC2wM/lLSH7d9OVmkCfEREjzz9Mfj1tpdOcX4dsEPb/vbAbRNcc4ntB4CbJK2hCPiXTVZohmgiImahT0M0lwG7SNpZ0qOAI4EVHdd8E3gegKSFFEM2N05VaHrwERGz0I9nOmw/KOktwAXAPOAM29dJOgFYaXtFee6FklZTrGP9Dtt3TFVuAnxERM+mP8+9a0n2+cD5HceOb9s28PbyNS0jMUQj6RhJn6q6HRERD+P+Peg0CJX14CXNs72xqvojImbLgDfWNxfNjHrwkh4r6duSrpJ0raQjJO0r6cflsUslLZC0SNIPJV1evp5Vvv9ASd8vH7G9pjz26vJ9V0o6vXyiC0mvk/Sfkn4APLvfHzwioh+a1INfBtxm+8UAkrYArgCOsH2ZpMcD9wK/Al5g+w/l47VfBcanCO0H7GH7JklPBY6gePT2AUmnAUdL+g7wD8ASYAPw/bKeiIj6qDiAdzPTAH8NcIqkk4DzgN8Ct9u+DMD2XVD09IFPSdqL4m7vrm1lXGr7pnL7+RRB/LIy4998il8O+wMX2f51Wd5ZHWU8RNJyYPkMP0dERF/0IxfNoMwowNv+T0lLgIOBDwEX8sinrQD+Dvgl8HSKYaA/tJ27p21bwBdsv7v9zZJeNkm5E7VpDBgr31ffn3RENFKde/AzHYPfFvi97X8BTgGeAWwrad/y/AJJmwJbUPTsW8BrKOZ1TuR7wGHjWdEkbS1pJ+CnwIGSniBpM+CVPXy2iIiB6me64EGY6RDN04CTJbWAB4C/puiFf1LSfIrx94OA04BvSHolxfj5PRMVZnu1pPcBF0rapCzzzbYvkfQB4CfA7cDlTP5LIiKiGjau8YIfMx2iuYDiaapOz+jY/xmwZ9v+u8v3XwRc1FHmWcBZE9R1JnDmTNoXETFsWZM1IqKh6jwGnwAfEdErJ8BHRDTS+E3WukqAj4jomWltrO8gfAJ8RESvMkQTEdFgCfAREc1U4/ieAB/VKHMPDcUwv0IP83NF9XKTNSKiqaa/6HYlEuAjInpmWk1JVRAREQ+XIZqIiKZKgI+IaB5nDD4iorlq3IFPgI+I6F2z1mSNiIhxJrNoIiKayNR7DH5Ga7IOkqQtJf1N1e2IiJiJOq/JWpsAD2wJJMBHxAhxOZWmy6sidRqi+SfgSZKuBL5THnsRxbegE8u1WyMi6qPm6YLr1IM/Dvh/tvcCLgH2Ap4OHAScLOmJVTYuImIirY3u+qpKnQJ8uwOAr9reaPuXwA+AfSe6UNJySSslrRxqCyNizhvPJlnXMfg6DdG0m3bOVdtjwBiApPp+V4qI5skQzbTdDSwoty8GjpA0T9I2wJ8Bl1bWsoiICXXvvacHD9i+Q9KPJF0L/BtwNXAVxbegd9r+r0obGBExgTr34GsT4AFsv6rj0DsqaUhExDTlQaeIiAYazybZ7TUdkpZJWiNpraTjprjuMEmWtLRbmQnwERGz0I8xeEnzgFMpnv1ZDBwlafEE1y0A/hb46XTalgAfEdGzvt1k3Q9Ya/tG2/cDXwMOneC6fwQ+DPxhOoUmwEdE9Kp/QzTbAbe07a8rjz1E0t7ADrbPm27zanWTNSJi1Eyzh76w42HMsfIZnnETPfvzUMGSNgE+Chwzk7YlwEdE9Gj8SdZpWG97qpui64Ad2va3B25r218A7AFcJAngT4EVkg6xPelT/AnwERE9M+7Pgh+XAbtI2hm4FTgSeGjauO0NwMLxfUkXAcdOFdwhY/AREb0zuNX91bUY+0HgLcAFwPXA121fJ+kESYf02rz04KPxyq+0QzHMpxqH+blicv36O7d9PnB+x7HjJ7n2wOmUmQAfETELSVUQEdFAM7jJWokE+IiIXtm0NvblJutAJMBHRMxGevAREc1kEuAjIhrHNV/RKQE+IqJnxtOZ6F6RBPiIiFlIDz4ioqFa/UlVMBC1CPCSPgD8Dng8cLHt71bbooiI7op87wnw0zLZY7kREbVV4yGaypKNSXpvuf7gd4HdymOfl3RYub1E0g8krZJ0gaQnVtXWiIjJeBr/VaWSAC9pCUU6zL2B/wHs23F+M+CTwGG2lwBnAB8cdjsjIrrp05J9A1HVEM1zgHNt/x5A0oqO87tRJLf/Tpkxbx5w+0QFSVoOLB9cUyMiJmNarY1VN2JSVY7BT/VrTcB1tp/ZtZBi2asxAEn1HQyLiMap+4NOVY3BXwy8XNJ8SQuAl3acXwNsI+mZUAzZSNp92I2MiOgmQzQdbF8u6SzgSuBm4Icd5+8vb7Z+QtIWFO38GHDd0BsbETGFOvfgKxuisf1BprhxavtK4M+G16KIiJlyradJ1moefETEqDF50CkionHspCqIiGioam+idpMAHxExC8lFExHRUOnBR0Q0VAJ8REQTOdMkIyIayUDLyUUTMSdIw8v+sXFI0/PmbVJZVvERkFk0ERGNlQAfEdFQCfAREQ1U3GPNPPiIiAYyTqqCiIhmqnLN1W4S4CMiZiFj8BERjeRaj8FngmtERI/G12Ttx5J9kpZJWiNpraTjJjj/dkmrJV0t6XuSdupWZgJ8RMQs9CPAS5oHnAq8CFgMHCVpccdlVwBLbe8JnAN8uFu5CfAREbPQarW6vqZhP2Ct7Rtt3w98DTi0/QLb37f9+3L3EmD7boUmwEdE9MzgVvdXd9sBt7TtryuPTeb1wL91KzQ3WSMiZmGa0yQXSlrZtj9me6xtXxMWPQFJrwaWAs/tVmkCfEREj8Zvsk7DettLpzi/DtihbX974LbOiyQdBLwXeK7t+7pVOvIBXtJyYHnV7YiIualP8+AvA3aRtDNwK3Ak8Kr2CyTtDZwOLLP9q+kUOvIBvvyaMwYgqb5PHEREA/VnHrztByW9BbgAmAecYfs6SScAK22vAE4GHgecLQngF7YPmarckQ/wERFVmuYsma5snw+c33Hs+Lbtg2Za5sjMopF0vqRtq25HRMS4fj7oNAgj04O3fXDVbYiIeLisyRoR0VimvrloEuAjImYh2SQjIhrJfbvJOggJ8BERPcqSfRERDZYhmoiIhkqAj4hopEyTjIhorCy6HTFnDO8f+y83bBhKPVtssc1Q6gHYsOHXQ6urH2xotTZW3YxJJcBHRPSs2lQE3STAR0TMQgJ8RERDJcBHRDRUHnSKiGgiZ5pkREQjGWilBx8R0UwZoomIaKRMk4yIaKw6B/hZr8kq6SJJayRdWb7OaTu3XNIN5etSSQe0nXuJpCskXSVptaQ3zbYtERHD1Mg1WSU9CtjM9j3loaNtr+y45iXAm4ADbK+XtA/wTUn7AXcAY8B+ttdJejSwqHzfVrbv7O3jREQMk3GNUxXMqAcv6amSPgKsAXbtcvm7gHfYXg9g+3LgC8CbgQUUv1zuKM/dZ3tN+b4jJF0r6VhJw0uCERHRA0/jv6p0DfCSHivpdZL+A/gccD2wp+0r2i77ctsQzcnlsd2BVR3FrQR2t/0bYAVws6SvSjpa0iYAtj8DvAiYD1ws6RxJy8bPR0TUyagP0dwOXA28wfYNk1zziCGaSYgy3Z7tN0h6GnAQcCzwAuCY8twtwD9KOhFYBvxvil8WhzyiQGk5sHwadUdE9N2o32Q9DLgVOFfS8ZJ2mmbZq4ElHcf2KY8DYPsa2x+lCO6vaL+wHKs/DfgkcDbw7okqsT1me6ntpdNsV0REXxQ99FbXV1W6BnjbF9o+AjgA2AB8S9J3JS3q8tYPAydJegKApL0oeuinSXqcpAPbrt0LuLm87oWSrgZOBC4CFtt+m+3rZvC5IiKGYtSHaACwfQfwceDjZe+6/dbxlyXdW26vt32Q7RWStgN+LMnA3cCrbd8uaQHwTkmnA/cC91AOz1DceH2p7Ztn9ckiIoag1WrYk6y2L23bPnCK6z4NfHqC43cDB0/yns4bsxER9VXjMfg8yRoR0TNjGtaDj4iIPz7JWlcJ8BERs5AAHxHRUAnwERGNZFo1zkWTAB8R0aO6j8Env0tExGyMr8s61WsaypxbayStlXTcBOcfLems8vxPp/GwaQJ8RETvppNLsnuAlzQPOJUi0eJi4ChJizsuez1wp+0nAx8FTupWbtOGaNZTpjyYgYXl+4YhdY1GPSNR17ZbbTW0unpU9/8vpptXa0p9yjWzH7DW9o0Akr4GHEpb7q5y/wPl9jnApyTJU4wRNSrA255x/nhJK4eVqCx1jUY9qWu06hrmZ5pIn1IVbAfc0ra/Dth/smtsPyhpA/AEpvjl1qgAHxExZBdQfIPoZnNJ7SnVx2yPte1rgvd09sync83DJMBHRPTI9rI+FbUO2KFtf3vgtkmuWSdpU2AL4DdTFZqbrMXasKlrNOpq4mdKXaNTzyBdBuwiaedyzesjKVa9a7cCeG25fRjwf6cafwdQnedwRkTMFZIOBj4GzAPOsP1BSScAK8v065sDXwL2pui5Hzl+U3bSMhPgIyKaKUM0ERENlQAfEdFQCfAREQ2VAB8R0VAJ8BERDZUAHxHRUAnwERENlQAfEdFQ/x/aA3II2xQ/7AAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "input = c est un jeune directeur plein de talent .\n",
      "output = he is a smart young drunk . <EOS>\n",
      "torch.Size([8, 10])\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "evaluateAndShowAttention(\"je suis trop froid .\")\n",
    "evaluateAndShowAttention(\"elle a cinq ans de moins que moi .\")\n",
    "evaluateAndShowAttention(\"elle est trop petit .\")\n",
    "evaluateAndShowAttention(\"je ne crains pas de mourir .\")\n",
    "evaluateAndShowAttention(\"c est un jeune directeur plein de talent .\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-03T07:12:44.915877Z",
     "start_time": "2019-11-03T07:12:44.913744Z"
    }
   },
   "source": [
    "### Save Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T12:14:19.259011Z",
     "start_time": "2019-11-12T12:14:19.157127Z"
    }
   },
   "outputs": [],
   "source": [
    "torch.save(enc.state_dict(), 'seq2seq-enc-cuda.pkl')\n",
    "torch.save(dec.state_dict(), 'seq2seq-dec-cuda.pkl')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-11-12T12:14:19.481820Z",
     "start_time": "2019-11-12T12:14:19.265032Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<All keys matched successfully>"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "enc.load_state_dict(torch.load('seq2seq-enc-cuda.pkl'))\n",
    "dec.load_state_dict(torch.load('seq2seq-dec-cuda.pkl'))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "oldHeight": 511.99678000000006,
   "position": {
    "height": "533.969px",
    "left": "412.875px",
    "right": "20px",
    "top": "161.969px",
    "width": "760.516px"
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "varInspector_section_display": "block",
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
